home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / sessmgr.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  25KB  |  1,111 lines

  1. /*
  2.  * Session manager and session manager switch
  3.  *
  4.  * The session manager switch intercepts all session and console I/O calls and
  5.  * forwards them to session managers based on the switch entry managing the
  6.  * session, or the system default session manager for new sessions.  New
  7.  * sessions may also be started attached to specific session managers.
  8.  * Sessions can also be "reparented" from one session manager to another.
  9.  *
  10.  * Per-session options are now supported.  Per-session-*manager* options have
  11.  * assigned slots in the session manager definition, but are not yet supported.
  12.  */
  13.  
  14. #include "global.h"
  15. #include "hardware.h"
  16. #include "proc.h"
  17. #include "socket.h"
  18. #undef tputs
  19. #include "tty.h"
  20. #include "sessmgr.h"
  21. #include "cmdparse.h"
  22. #include "commands.h"
  23. #include "config.h"
  24.  
  25. static int dosmstatus __ARGS((int, char **, void *));
  26. static int dosmdefault __ARGS((int, char **, void *));
  27. static int dosmcreate __ARGS((int, char **, void *));
  28. static int dosmreparent __ARGS((int, char **, void *));
  29. static int dosmoptions __ARGS((int, char **, void *));
  30.  
  31. /*
  32.  * The session manager switch:  an array of pointers to session managers.
  33.  */ 
  34.  
  35. #ifdef SM_CURSES
  36. extern struct sessmgr_sw curses_sessmgr;
  37. #endif
  38. #ifdef SM_RAW
  39. extern struct sessmgr_sw raw_sessmgr;
  40. #endif
  41. #ifdef SM_DUMB
  42. extern struct sessmgr_sw dumb_sessmgr;
  43. #endif
  44.  
  45. static struct sessmgr_sw *sessmgr_sw[] =
  46. {
  47. #ifdef SM_CURSES
  48.     &curses_sessmgr,
  49. #endif
  50. #ifdef SM_DUMB
  51.     &dumb_sessmgr,
  52. #endif
  53. #ifdef SM_RAW
  54.     &raw_sessmgr,
  55. #endif
  56.     0,
  57. };
  58.  
  59. static int sesm_initted;
  60.  
  61. /*
  62.  * Commands for session manager administration
  63.  */
  64.  
  65. static struct cmds SMcmds[] =
  66. {
  67.     "create",    dosmcreate,    0,    0,    NULLCHAR,
  68.     "default",    dosmdefault,    0,    0,    NULLCHAR,
  69.     "options",    dosmoptions,    0,    0,    NULLCHAR,
  70.     "reparent",    dosmreparent,    0,    0,    NULLCHAR,
  71.     "status",    dosmstatus,    0,    0,    NULLCHAR,
  72.     NULLCHAR,    NULLFP((int,char**,void*)),    0,    0,    NULLCHAR,
  73. };
  74.  
  75. static struct cmds SMsessions[] =
  76. {
  77. #ifdef MAILBOX
  78.     "bbs",    dobbs,        1024,    0,    NULLCHAR,
  79. #endif
  80. #ifdef AX25
  81. #ifdef ALLSESSIONS
  82.     "connect",    doconnect,    1024,    3,
  83.     "connect <interface> <callsign>",
  84. #endif
  85. #endif
  86. #ifdef ALLCMD
  87.     "dir",    dodir,        0,    0,    NULLCHAR,
  88. #endif
  89. #ifdef DIALER
  90.     "dialer",    dodialer,    512,    2,
  91.     "dialer <iface> [<file> [<seconds> [<pings> [<hostid>]]]]",
  92. #endif
  93. #ifdef ALLCMD
  94.     "finger",    dofinger,    1024,    2,    "finger name[@host]",
  95. #endif
  96. #ifdef ALLSESSIONS
  97.     "ftp",    doftp,        2048,    2,    "ftp <address>",
  98. #endif
  99. #ifdef HOPCHECK
  100.     /* hopcheck - need to restrict to hopcheck itself */
  101. #endif
  102. #ifdef ALLCMD
  103.     "more",    domore,        0,    2,    "more <file> [searchstring]",
  104. #endif
  105. #ifdef NETROM
  106.     /* netrom connect */
  107. #endif
  108.     "ping",    doping,        512,    4,
  109.     "ping <hostid> <length> <interval> [incflag]",
  110. #ifdef RLOGINCLI
  111.     "rlogin",    dorlogin,    2048,    2,    "rlogin <address>",
  112. #endif
  113. #ifdef AX25
  114. #ifdef ALLSESSIONS
  115. #ifdef ALLSERV
  116.     "split",    doconnect,    1024,    3,
  117.     "split <interface> <callsign>",
  118. #endif
  119. #endif
  120. #endif
  121. #ifdef ALLSESSIONS
  122.     "telnet",    dotelnet,    1024,    2,    "telnet <address> [port]",
  123. #endif
  124. #ifdef ALLSERV
  125.     "ttylink",    dotelnet,    1024,    2,    "ttylink <address> [port]",
  126. #endif
  127.     NULLCHAR,    NULLFP((int,char**,void*)),    0,    0,    NULLCHAR,
  128. };
  129.  
  130. /*
  131.  * Used by the newscreen() entry point, the creation of the trace session
  132.  * in main(), and by reparenting.
  133.  */
  134.  
  135. static void
  136. sm_newscreen(char *sc, struct session *sp)
  137. {
  138.     struct sessmgr_sw *sm;
  139.     char *cp;
  140.  
  141.     if (!(sm = sm_lookup(sc, &cp)))
  142.     {
  143.     sm = sessmgr_sw[0];    /* system-wide default session manager */
  144.     cp = 0;
  145.     }
  146.     if (!sp)
  147.     return;
  148.     sp->screen = mallocw(sizeof *sp->screen);
  149.     if (!(sm->flags & SM_INIT))
  150.     {
  151.     if (Current && Current != sp && Current->screen &&
  152.         !(Current->screen->sessmgr->flags & SM_SUSPEND))
  153.     {
  154.         (*Current->screen->sessmgr->suspend)(Current->screen->sessmgr);
  155.         Current->screen->sessmgr->flags |= SM_SUSPEND;
  156.     }
  157.     (*sm->init)(sm);
  158.     sm->flags |= SM_INIT;
  159.     }
  160.     sm->refcnt++;
  161.     sp->screen->sessmgr = sm;
  162.     sp->screen->sesmdat =
  163.     (*sm->create)(sm, sp);
  164.     if (sm->sessopt && cp)
  165.     (*sm->sessopt)(sm, sp->screen->sesmdat, cp);
  166.     sp->screen->flags = 0;
  167.     if (sp->split)
  168.     sp->screen->flags |= SMS_SPLIT;
  169.     if (!(sm->flags & SM_SPLIT))
  170.     sp->split = 0;    /* if sm can't do split, split sessions are deranged */
  171.     sp->screen->next_sm = strdup(sc);
  172.     sp->screen->use_sm = sp->screen->next_sm;
  173.     if (sm->flags & SM_SUSPEND)
  174.     {
  175.     (*Current->screen->sessmgr->resume)(Current->screen->sessmgr);
  176.     Current->screen->sessmgr->flags &= ~SM_SUSPEND;
  177.     }
  178. #if 0
  179.     /* this is ugly... */
  180.     /* (it's also wrong; figure it out later...) */
  181.     if (sp->type == TRACESESSION)
  182.     sp->screen->flags |= SMS_DISCARD;
  183. #endif
  184. }
  185.  
  186. int
  187. dosessmgr(int argc, char **argv, void *p)
  188. {
  189.     if (argc < 2)
  190.     return dosmstatus(argc, argv, p);
  191.     return subcmd(SMcmds, argc, argv, p);
  192. }
  193.  
  194. int
  195. dosmstatus(int argc, char **argv, void *p)
  196. {
  197.     struct screen *sp;
  198.     char *cp;
  199.     int s;
  200.  
  201.     tprintf("Known session managers are:\n");
  202.     for (s = 0; sessmgr_sw[s]; s++)
  203.     tprintf("%s\n", sessmgr_sw[s]->name);
  204.     tprintf("\n");
  205.     dosmdefault(0, 0, 0);
  206.     tprintf("\n#  Type         Name         Process      Manager  Options\n");
  207.     tprintf("== ============ ============ ============ ======== ==========\n");
  208.     for (s = 0; s < Nsessions; s++)
  209.     {
  210.     if (Sessions[s].type == FREE)
  211.         continue;
  212.     tprintf("%-2d %-12s ", s, Sestypes[Sessions[s].type]);
  213.     if (Sessions[s].name)
  214.         tprintf("%-12.12s ", Sessions[s].name);
  215.     else
  216.         tprintf("             ");
  217.     if (Sessions[s].proc->name && *Sessions[s].proc->name)
  218.         tprintf("%-12.12s", Sessions[s].proc->name);
  219.     else
  220.         tprintf("%8.8lx    ", FP_SEG(Sessions[s].proc));
  221.     tprintf(" %-8.8s", Sessions[s].screen->sessmgr->name);
  222.     /* we don't support session MANAGER options just yet... */
  223.     if ((sp = Sessions[s].screen)->sessmgr->sessopt &&
  224.         (cp = (*sp->sessmgr->sessopt)(sp->sessmgr, sp->sesmdat,(char *)0)))
  225.         tprintf(" %s", cp);
  226.     tprintf("\n");
  227.     }
  228.     return 0;
  229. }
  230.  
  231. int
  232. dosmdefault(int argc, char **argv, void *p)
  233. {
  234.     char *cp;
  235.  
  236.     if (argc < 2)
  237.     {
  238.     if (Current && Current->screen && Current->type == COMMAND)
  239.         cp = Current->screen->next_sm;
  240.     else if (Command && Command->screen)
  241.         cp = Command->screen->next_sm;
  242.     else
  243.         cp = "";
  244.     if (!cp || !*cp)
  245.         cp = sessmgr_sw[0]->name;
  246.     tprintf("Session manager for new sessions is \"%s\".\n", cp);
  247.     return 0;
  248.     }
  249.     if (argc > 2)
  250.     {
  251.     tprintf("usage: sessmgr default [session-manager]\n");
  252.     return 1;
  253.     }
  254.     if (!sm_lookup(argv[1], 0))
  255.     {
  256.     tprintf("No such session manager: \"%s\"\n", argv[1]);
  257.     return 1;
  258.     }
  259.     if (Current->screen->next_sm)
  260.     free(Current->screen->next_sm);
  261.     Current->screen->next_sm = strdup(argv[1]);
  262.     return 0;
  263. }
  264.  
  265. int
  266. dosmcreate(int argc, char **argv, void *p)
  267. {
  268.     int rc;
  269.  
  270.     if (argc < 3)
  271.     {
  272.     tprintf("usage: sessmgr create session-manager command [args...]\n");
  273.     return 1;
  274.     }
  275.     if (!sm_lookup(argv[1], 0))
  276.     {
  277.     tprintf("Unknown session manager \"%s\"\n", argv[1]);
  278.     return 1;
  279.     }
  280.     if (Current->type != COMMAND)
  281.     write(2, "WHOA! I'm not being run from a COMMAND session!\n", 48);
  282.     Current->screen->use_sm = argv[1];
  283.     rc = subcmd(SMsessions, argc - 1, argv + 1, p);
  284.     return rc;
  285. }
  286.  
  287. int
  288. dosmoptions(int argc, char **argv, void *p)
  289. {
  290.     struct screen *sp;
  291.     char *cp;
  292.     int i;
  293.  
  294.     if (argc < 2)
  295.     {
  296.     tprintf("usage: sessmgr options session [options]\n");
  297.     return 1;
  298.     }
  299.     if ((i = atoi(argv[1])) < 0 || i > Nsessions || Sessions[i].type == FREE)
  300.     {
  301.     tprintf("Invalid session %s\n", argv[1]);
  302.     return 1;
  303.     }
  304.     sp = Sessions[i].screen;
  305.     if (argc < 3)
  306.     {
  307.     tprintf("Options for session: ");
  308.     if (!sp->sessmgr->sessopt)
  309.         cp = 0;
  310.     else
  311.         cp = (*sp->sessmgr->sessopt)(sp->sessmgr, sp->sesmdat, (char *) 0);
  312.     if (!cp)
  313.         cp = "(none)";
  314.     tprintf("%s\n", cp);
  315.     return 0;
  316.     }
  317.     if (sp->sessmgr->sessopt)
  318.     (*sp->sessmgr->sessopt)(sp->sessmgr, sp, argv[2]);
  319.     return 0;
  320. }
  321.  
  322. /*
  323.  * Administration of the session manager interface
  324.  */
  325.  
  326. struct sessmgr_sw *
  327. sm_lookup(char *smname, char **optp)
  328. {
  329.     static char buf[1024];
  330.     char *cp;
  331.     int i;
  332.  
  333.     if (!smname)
  334.     {
  335.     /* inherit a reasonable session manager */
  336.     if (Current && Current->screen && Current->type == COMMAND)
  337.     {
  338.         smname = Current->screen->use_sm;
  339.         Current->screen->use_sm = Current->screen->next_sm;
  340.     }
  341.     else if (Command && Command->screen)
  342.         smname = Command->screen->next_sm;
  343.     else
  344.         smname = "";
  345.     }
  346.     i = 0;
  347.     for (cp = smname; *cp && *cp != ':'; cp++)
  348.     buf[i++] = *cp;
  349.     buf[i] = '\0';
  350.     if (*cp)
  351.     cp++;
  352.     else
  353.     cp = 0;
  354.     if (!i)
  355.     {
  356.     if (optp)        /* is this wise?  sessmgr ":opt", that is */
  357.         *optp = cp;
  358.     return sessmgr_sw[0];
  359.     }
  360.     for (i = 0; sessmgr_sw[i]; i++)
  361.     {
  362.     if (strcasecmp(sessmgr_sw[i]->name, buf) == 0)
  363.     {
  364.         if (optp)
  365.         *optp = cp;
  366.         return sessmgr_sw[i];
  367.     }
  368.     }
  369.     if (optp)
  370.     *optp = 0;
  371.     return 0;
  372. }
  373.  
  374. int
  375. sm_blocked(struct session *sp)
  376. {
  377.     /* Return TRUE if the session is blocked. */
  378.     return !(sp->screen->flags & SMS_ACTIVE) ||
  379.     (sp->screen->sessmgr->flags & SM_SUSPEND);
  380. }
  381.  
  382. /*
  383.  * Session reparenting.  This is mildly interesting.
  384.  *
  385.  * The idea is that a session can be destroyed and recreated.  (Actually, the
  386.  * session is retained; the screen is destroyed.)  The only fly in the oint-
  387.  * ment is that you can't retain the contents of the screen:  some session
  388.  * managers have no backing store ("dumb", and especially "none").
  389.  *
  390.  * Sessions can be reparented individually or by session manager.  Individual
  391.  * sessions can be named if they have names.
  392.  */
  393.  
  394. static void
  395. sm_reparent(struct session *sp, char *new)
  396. {
  397.     struct sessmgr_sw *old, *np;
  398.     int susp;
  399.  
  400.     if (!(np = sm_lookup(new, 0)))
  401.     return;
  402.     if ((old = sp->screen->sessmgr) == np)
  403.     return;
  404.     if (sp->screen->flags & SMS_SPLIT) /* sp->split is 0 if s.m. won't split */
  405.     sp->split = 1;        /* newscreen will deactivate if needed */
  406.     susp = (old->flags & SM_STDIO) && (np->flags & SM_STDIO);
  407.     freescreen(sp);
  408.     if (susp && !(old->flags & SM_SUSPEND))
  409.     {
  410.     (*old->suspend)(old);
  411.     old->flags |= SM_SUSPEND;
  412.     }
  413.     sm_newscreen(new, sp);
  414. }
  415.  
  416. int
  417. dosmreparent(int argc, char **argv, void *p)
  418. {
  419.     struct sessmgr_sw *old;
  420.     struct session *s;
  421.     int i, susp;
  422.  
  423.     if (argc != 3)
  424.     {
  425.     tprintf("usage: sessmgr reparent <session> <session-manager>\n");
  426.     return 1;
  427.     }
  428.     if (!sm_lookup(argv[2], 0))
  429.     {
  430.     tprintf("Unknown session manager \"%s\"\n", argv[2]);
  431.     return -1;
  432.     }
  433.     if (isdigit(argv[1][0]))
  434.     {
  435.     if ((i = atoi(argv[1])) >= Nsessions || Sessions[i].type == FREE)
  436.     {
  437.         tprintf("Invalid session number %d.\n", i);
  438.         return 1;
  439.     }
  440.     sm_reparent(Sessions + i, argv[2]);
  441.     if (Sessions + i == Current)
  442.         Sessions[i].screen->flags |= SMS_ACTIVE;
  443.     else
  444.     {
  445.         /* we must do this because newscreen() partially switches us */
  446.         swapscreen(Current, Sessions + i);
  447.         swapscreen(Sessions + i, Current);
  448.     }
  449.     return 0;
  450.     }
  451.     susp = -1;
  452.     for (i = 0; i < Nsessions; i++)
  453.     {
  454.     if (Sessions[i].type == FREE)
  455.         continue;
  456.     if (Sessions[i].name && *Sessions[i].name &&
  457.         strcasecmp(Sessions[i].name, argv[1]) == 0)
  458.     {
  459.         if (susp != -1)
  460.         break;
  461.         susp = i;
  462.     }
  463.     if (Sessions[i].proc->name && *Sessions[i].proc->name &&
  464.         strcasecmp(Sessions[i].proc->name, argv[1]) == 0)
  465.     {
  466.         if (susp != -1)
  467.         break;
  468.         susp = i;
  469.     }
  470.     if (strcasecmp(Sestypes[Sessions[i].type], argv[1]) == 0)
  471.     {
  472.         if (susp != -1)
  473.         break;
  474.         susp = i;
  475.     }
  476.     }
  477.     if (i != Nsessions)
  478.     {
  479.     tprintf("Session ID \"%s\" is not unique\n", argv[1]);
  480.     return 1;
  481.     }
  482.     if (susp != -1)
  483.     {
  484.     sm_reparent(Sessions + susp, argv[2]);
  485.     if (Sessions + susp == Current)
  486.         Sessions[susp].screen->flags |= SMS_ACTIVE;
  487.     else
  488.     {
  489.         /* we must do this because newscreen() partially switches us */
  490.         swapscreen(Current, Sessions + susp);
  491.         swapscreen(Sessions + susp, Current);
  492.     }
  493.     return 0;
  494.     }
  495.     for (i = 0; sessmgr_sw[i]; i++)
  496.     {
  497.     if (sessmgr_sw[i]->refcnt &&
  498.         strcasecmp(sessmgr_sw[i]->name, argv[1]) == 0)
  499.         break;
  500.     }
  501.     if (!sessmgr_sw[i])
  502.     {
  503.     tprintf("Can't decipher session ID \"%s\"\n", argv[1]);
  504.     return 1;
  505.     }
  506.     /* reparent all of them! */
  507.     old = sessmgr_sw[i];
  508.     s = Current;
  509.     for (i = 0; i < Nsessions; i++)
  510.     {
  511.     if (Sessions[i].screen->sessmgr != old)
  512.         continue;
  513.     sm_reparent(Sessions + i, argv[2]);
  514.     swapscreen(s, Sessions + i);
  515.     s = Sessions + i;
  516.     }
  517.     if (s == Current)
  518.     Sessions[i].screen->flags |= SMS_ACTIVE;
  519.     else
  520.     swapscreen(s, Current);
  521.     return 0;
  522. }
  523.  
  524. /*
  525.  * Ugly hack for doshell():  tell if the current session manager is SM_STDIO.
  526.  */
  527.  
  528. int
  529. sm_usestdio(void)
  530. {
  531.     return Current->screen->sessmgr->flags & SM_STDIO;
  532. }
  533.  
  534. /*
  535.  * Start a session with a specified session manager.  This could be static
  536.  * since it's normally only used by the "sessmgr <sm> create" command, but
  537.  * we also need it to start the trace session in a different session manager
  538.  * from the default.
  539.  *
  540.  * This incorporates newsession().  Ultimately, newsession() should be changed
  541.  * to call this function.
  542.  */
  543.  
  544. struct session *
  545. sm_newsession(char *sc, char *name, int type, int split)
  546. {
  547.     extern int Numrows;
  548.     struct session *sp;
  549.     int i;
  550.  
  551.     if (!sc || !*sc)
  552.     {
  553.     /*
  554.      * HACK - new sessions should inherit the current session if it is a
  555.      * COMMAND session.  Else use Command's next session, unless Command
  556.      * doesn't exist yet (creation of Command or Trace) in which case the
  557.      * default session manager is used.
  558.      *
  559.      * Maybe this isn't really a hack... but it feels like one.
  560.      */
  561.     if (Current && Current->screen && Current->type == COMMAND)
  562.         sc = Current->screen->next_sm;
  563.     else if (Command && Command->screen)
  564.         sc = Command->screen->next_sm;
  565.     else
  566.         sc = "";
  567.     }
  568.     if (type == TRACESESSION)
  569.     i = Nsessions - 1;
  570.     else
  571.     {
  572.     for (i = 0; i < Nsessions; i++)
  573.     {
  574.         if (Sessions[i].type == FREE)
  575.         break;
  576.     }
  577.     }
  578.     if (i == Nsessions)
  579.     return NULLSESSION;
  580.     sp = Sessions + i;
  581.     sp->type = type;
  582.     sp->s = -1;
  583.     if (name != NULLCHAR)
  584.     sp->name = strdup(name);
  585.     sp->proc = Curproc;
  586.     /* update Curproc's session pointer as well! */
  587.     /* (in theory this could leave a dangling session...?) */
  588.     Curproc->session = sp;
  589.     /* Create standard input and output sockets. Output is
  590.      * translated to local end-of-line by default
  591.      */
  592.     Curproc->input = sp->input = socket(AF_LOCAL, SOCK_STREAM, 0);
  593.     seteol(Curproc->input, Eol);
  594.     sockmode(Curproc->input, SOCK_BINARY);
  595.     Curproc->output = sp->output = socket(AF_LOCAL, SOCK_STREAM, 0);
  596.     seteol(Curproc->output, Eol);
  597.     sockmode(Curproc->output, SOCK_ASCII);
  598.     /* on by default */
  599.     sp->ttystate.crnl = sp->ttystate.edit = sp->ttystate.echo = 1;
  600.     sp->flowmode = 0;    /* Off by default */
  601.     sp->row = Numrows;
  602.     sp->morewait = 0;
  603.     sp->split = split;
  604.     sm_newscreen(sc, sp);
  605.     swapscreen(Current, sp);
  606.     Current = sp;
  607.     return sp;
  608. }
  609.  
  610. /*
  611.  * Session manager initiation and cleanup.
  612.  */
  613.  
  614. void
  615. ioinit(int no_itimer)
  616. {
  617.     init_sys(no_itimer);
  618.     sesm_initted = 1;
  619. }
  620.  
  621. void
  622. iostop(void)
  623. {
  624.     int c;
  625.  
  626.     sesm_initted = 0;
  627.     for (c = 0; sessmgr_sw[c]; c++)
  628.     {
  629.     if (sessmgr_sw[c]->flags & SM_INIT)
  630.         (*sessmgr_sw[c]->end)(sessmgr_sw[c]);
  631.     }
  632.     deinit_sys();
  633. }
  634.  
  635. /*
  636.  * Suspend and resume now only suspend/resume the current session manager.
  637.  * It is assumed that the session manger is SM_STDIO and that an outside
  638.  * process needs to intercept the SM_STDIO interface temporarily.
  639.  */
  640.  
  641. void
  642. iosuspend(void)
  643. {
  644.     register struct screen *sp = Current->screen;
  645.  
  646.     if ((sp->sessmgr->flags & (SM_INIT|SM_SUSPEND)) == SM_INIT)
  647.     {
  648.     (*sp->sessmgr->suspend)(sp->sessmgr);
  649.     sp->sessmgr->flags |= SM_SUSPEND;
  650.     }
  651. }
  652.  
  653. void
  654. ioresume(void)
  655. {
  656.     register struct screen *sp = Current->screen;
  657.  
  658.     if ((sp->sessmgr->flags & (SM_INIT|SM_SUSPEND)) == (SM_INIT|SM_SUSPEND))
  659.     {
  660.     (*sp->sessmgr->resume)(sp->sessmgr);
  661.     sp->sessmgr->flags &= ~SM_SUSPEND;
  662.     }
  663. }
  664.  
  665. /*
  666.  * Session creation, destruction, and swapping.
  667.  */
  668.  
  669. void
  670. j_newscreen(struct session *sp)
  671. {
  672.     char *sc;
  673.  
  674.     if (Current && Current->screen && Current->type == COMMAND)
  675.     {
  676.     sc = Current->screen->use_sm;
  677.     Current->screen->use_sm = Current->screen->next_sm;
  678.     }
  679.     else if (Command && Command->screen)
  680.     sc = Command->screen->next_sm;
  681.     else
  682.     sc = "";
  683.     sm_newscreen(sc, sp);
  684. }
  685.  
  686. void
  687. freescreen(struct session *sp)
  688. {
  689.     if (!sp || !sp->screen)
  690.     return;
  691.     (*sp->screen->sessmgr->destroy)(sp->screen->sessmgr, sp->screen->sesmdat);
  692.     free(sp->screen->next_sm);
  693.     if (!--sp->screen->sessmgr->refcnt)
  694.     {
  695.     (*sp->screen->sessmgr->end)(sp->screen->sessmgr);
  696.     sp->screen->sessmgr->flags &= ~SM_INIT;
  697.     }
  698.     free(sp->screen);
  699.     sp->screen = 0;
  700. }
  701.  
  702. void
  703. swapscreen(struct session *old, struct session *new)
  704. {
  705.     if (old == new)
  706.     return;
  707.     /*
  708.      * If they're in different session managers, swap each to/from NULL.
  709.      * Otherwise, swap them in the common session manager.
  710.      */
  711.     if (old && new && old->screen->sessmgr == new->screen->sessmgr)
  712.     {
  713.     if (!(*old->screen->sessmgr->swtch)(old->screen->sessmgr,
  714.                         old->screen->sesmdat,
  715.                         new->screen->sesmdat))
  716.         old->screen->flags &= ~SMS_ACTIVE;
  717.     }
  718.     else
  719.     {
  720.     if (old)
  721.     {
  722.         (*old->screen->sessmgr->swtch)(old->screen->sessmgr,
  723.                        old->screen->sesmdat, 0);
  724.     }
  725.     if (old && new && (old->screen->sessmgr->flags & SM_STDIO) &&
  726.         (new->screen->sessmgr->flags & SM_STDIO) &&
  727.         !(old->screen->sessmgr->flags & SM_SUSPEND))
  728.     {
  729.         (*old->screen->sessmgr->suspend)(old->screen->sessmgr);
  730.         old->screen->sessmgr->flags |= SM_SUSPEND;
  731.     }
  732.     if (new &&
  733.         ((new->screen->sessmgr->flags & (SM_SUSPEND|SM_STDIO|SM_INIT)) ==
  734.          (SM_SUSPEND|SM_STDIO|SM_INIT)))
  735.     {
  736.         (*new->screen->sessmgr->resume)(new->screen->sessmgr);
  737.         new->screen->sessmgr->flags &= ~SM_SUSPEND;
  738.     }
  739.     if (new)
  740.     {
  741.         (*new->screen->sessmgr->swtch)(new->screen->sessmgr, 0,
  742.                        new->screen->sesmdat);
  743.     }
  744.     }
  745.     if (new)
  746.     {
  747.     new->screen->flags |= SMS_ACTIVE;
  748.     j_psignal(new->screen, 0);
  749.     }
  750. }
  751.  
  752. /*
  753.  * Some session managers (e.g. curses) aren't re-entrant.  We deal with this
  754.  * by locking individual screens.  (we assume the session manager is reentrant
  755.  * between separate screens; this may be unsafe...)
  756.  */
  757.  
  758. static int
  759. #ifdef __STDC__
  760. LOCKSCR(register struct screen *sc, int wait)
  761. #else
  762. LOCKSCR(sc, wait)
  763.     register struct screen *sc;
  764.     int wait;
  765. #endif
  766. {
  767.     sigset_t s, t;
  768.  
  769.     sigfillset(&s);
  770.     sigprocmask(SIG_BLOCK, &s, &t);
  771.     while (sc->flags & SM_LOCK)
  772.     {
  773.     if (!wait)
  774.         return 0;
  775.     pwait(&sc->flags);
  776.     }
  777.     sc->flags |= SM_LOCK;
  778.     sigprocmask(SIG_SETMASK, &t, 0);
  779.     return 1;
  780. }
  781.  
  782. static void
  783. #ifdef __STDC__
  784. UNLOCKSCR(register struct screen *sc)
  785. #else
  786. UNLOCKSCR(sc)
  787.     register struct screen *sc;
  788. #endif
  789. {
  790.     sigset_t s, t;
  791.  
  792.     sigfillset(&s);
  793.     sigprocmask(SIG_BLOCK, &s, &t);
  794.     sc->flags &= ~SM_LOCK;
  795.     j_psignal(&sc->flags, 0);
  796.     sigprocmask(SIG_SETMASK, &t, 0);
  797. }
  798.  
  799. /*
  800.  * I/O routines come in two flavors.  The internal ones, which start with
  801.  * "s", are used by rflush() and by the external ones.  The external ones are
  802.  * used by the rest of NOS.
  803.  */
  804.  
  805. static void
  806. sputch(struct session *s, int c)
  807. {
  808.     (*s->screen->sessmgr->putch)(s->screen->sessmgr, s->screen->sesmdat, c);
  809. }
  810.  
  811. static void
  812. scputs(struct session *s, char *str)
  813. {
  814.     register struct screen *sp;
  815.  
  816.     sp = s->screen;
  817.     while (*str)
  818.     (*sp->sessmgr->putch)(sp->sessmgr, sp->sesmdat, *str++);
  819. }
  820.  
  821. static void
  822. sclreol(struct session *s)
  823. {
  824.     (*s->screen->sessmgr->clreol)(s->screen->sessmgr, s->screen->sesmdat);
  825. }
  826.  
  827. /*
  828.  * rflush() used to flush data to the display process.  Now it does I/O itself;
  829.  * the display process is defunct.
  830.  */
  831.  
  832. void
  833. rflush(void)
  834. {
  835.     struct session *sp;
  836.     int i, c;
  837.  
  838.     if (!Sessions || !sesm_initted)
  839.     return;    /* timer could tick before we exist, or while suspended */
  840.     for (sp = Sessions, i = 0; i < Nsessions; sp++, i++)
  841.     {
  842.     if (sp->type == FREE)
  843.         continue;
  844.     if (!sp->screen || !sp->screen->sessmgr || !sp->screen->sesmdat)
  845.         continue;
  846.     if (!(sp->screen->flags & SMS_ACTIVE) || sp->morewait == 1)
  847.         continue;        
  848.     /* err, do I want to do this? */
  849.     if (sp->screen->sessmgr->flags & SM_SUSPEND)
  850.         continue;
  851.     if (!LOCKSCR(sp->screen, 0))
  852.     {
  853.         write(2, "screen not responding - still trying\r\n", 38);
  854.         continue;
  855.     }
  856.     (*sp->screen->sessmgr->rflush)(sp->screen->sessmgr,
  857.                        sp->screen->sesmdat);
  858.     if (sp->morewait == 2)
  859.     {
  860.         sp->morewait = 0;
  861.         sputch(sp, '\r');
  862.         sclreol(sp);
  863.     }
  864.     while (socklen(sp->output, 0) > 0)
  865.     {
  866.         if ((c = rrecvchar(sp->output)) == -1)
  867.         continue;
  868.         if (!sp->split || c != 0x0a)
  869.         sputch(sp, c);
  870.         else
  871.         {
  872.         scputs(sp, Eol);
  873.         sclreol(sp);
  874.         }
  875.         if (sp->record != NULLFILE)
  876.         {
  877.         if (c == '\r' || c == '\n')
  878.             fflush(sp->record);
  879.         if (c != '\r' || sockmode(sp->output, -1) != SOCK_ASCII)
  880.             putc(c, sp->record);
  881.         }
  882.         if (sp->flowmode && c == '\n' && sp->row > 0 && --sp->row == 0)
  883.         {
  884.         scputs(sp, "--More--");
  885.         sp->morewait = 1;
  886.         break;
  887.         }
  888.     }
  889.     (*sp->screen->sessmgr->flush)(sp->screen->sessmgr,
  890.                       sp->screen->sesmdat);
  891.     UNLOCKSCR(sp->screen);
  892.     }
  893. }
  894.  
  895. /*
  896.  * Public output routines.  getcursess() attempts to intuit the correct session
  897.  * for output.
  898.  */
  899.  
  900. static struct session *
  901. getcursess(void)
  902. {
  903.     static struct proc *kbproc;
  904.  
  905.     /* this is a horrible hack that will (MUST!) go away in the future */
  906.     if (!kbproc && Curproc && strcmp(Curproc->name, "keyboard") == 0)
  907.     kbproc = Curproc;
  908.     if (kbproc == Curproc)
  909.     return Current;
  910.     /*
  911.      * if Curproc's session isn't active we must block...
  912.      * N.B. should handle trace with a special flag indicating that the
  913.      * session should discard output instead of blocking
  914.      */
  915.     if (!(Curproc->session->screen->flags & SMS_ACTIVE))
  916.     {
  917. #if 0
  918.     if (Curproc->session->screen->flags & SMS_DISCARD)
  919.         return 0;
  920. #endif
  921.     pwait(Current->screen);
  922.     }
  923.     return Curproc->session;
  924. }
  925.  
  926. void
  927. putch(int c)
  928. {
  929.     struct session *sp;
  930.  
  931.     sp = getcursess();
  932.     LOCKSCR(sp->screen, 1);
  933.     sputch(sp, c);
  934.     UNLOCKSCR(sp->screen);
  935. }
  936.  
  937. void
  938. cputs(char *s)
  939. {
  940.     struct session *sp;
  941.  
  942.     sp = getcursess();
  943.     LOCKSCR(sp->screen, 1);
  944.     scputs(sp, s);
  945.     UNLOCKSCR(sp->screen);
  946. }
  947.  
  948. void
  949. clreol(void)
  950. {
  951.     struct session *sp;
  952.  
  953.     sp = getcursess();
  954.     LOCKSCR(sp->screen, 1);
  955.     sclreol(sp);
  956.     UNLOCKSCR(sp->screen);
  957. }
  958.  
  959. void
  960. clrscr(void)
  961. {
  962.     register struct screen *sp;
  963.  
  964.     sp = getcursess()->screen;
  965.     LOCKSCR(sp, 1);
  966.     (*sp->sessmgr->clrscr)(sp->sessmgr, sp->sesmdat);
  967.     UNLOCKSCR(sp);
  968. }
  969.  
  970. int
  971. wherex(void)
  972. {
  973.     register struct screen *sp;
  974.     int i;
  975.  
  976.     sp = getcursess()->screen;
  977.     if (sp->sessmgr->wherex)
  978.     {
  979.     LOCKSCR(sp, 1);
  980.     i = (*sp->sessmgr->wherex)(sp->sessmgr, sp->sesmdat);
  981.     UNLOCKSCR(sp);
  982.     return i;
  983.     }
  984.     return -1;
  985. }
  986.  
  987. int
  988. wherey(void)
  989. {
  990.     register struct screen *sp;
  991.     int i;
  992.  
  993.     sp = getcursess()->screen;
  994.     if (sp->sessmgr->wherey)
  995.     {
  996.     LOCKSCR(sp, 1);
  997.     i = (*sp->sessmgr->wherey)(sp->sessmgr, sp->sesmdat);
  998.     UNLOCKSCR(sp);
  999.     return i;
  1000.     }
  1001.     return -1;
  1002. }
  1003.  
  1004. void
  1005. window(int x1, int y1, int x2, int y2)
  1006. {
  1007.     register struct screen *sp;
  1008.  
  1009.     sp = getcursess()->screen;
  1010.     if (sp->sessmgr->window)
  1011.     {
  1012.     LOCKSCR(sp, 1);
  1013.     (*sp->sessmgr->window)(sp->sessmgr, sp->sesmdat, x1, y1, x2, y2);
  1014.     UNLOCKSCR(sp);
  1015.     }
  1016. }
  1017.  
  1018. void
  1019. gotoxy(int x, int y)
  1020. {
  1021.     register struct screen *sp;
  1022.  
  1023.     sp = getcursess()->screen;
  1024.     LOCKSCR(sp, 1);
  1025.     (*sp->sessmgr->gotoxy)(sp->sessmgr, sp->sesmdat, x, y);
  1026.     UNLOCKSCR(sp);
  1027. }
  1028.  
  1029. void
  1030. highvideo(void)
  1031. {
  1032.     register struct screen *sp;
  1033.  
  1034.     sp = getcursess()->screen;
  1035.     LOCKSCR(sp, 1);
  1036.     (*sp->sessmgr->high)(sp->sessmgr, sp->sesmdat);
  1037.     UNLOCKSCR(sp);
  1038. }
  1039.  
  1040. void
  1041. normvideo(void)
  1042. {
  1043.     register struct screen *sp;
  1044.  
  1045.     sp = getcursess()->screen;
  1046.     LOCKSCR(sp, 1);
  1047.     (*sp->sessmgr->norm)(sp->sessmgr, sp->sesmdat);
  1048.     UNLOCKSCR(sp);
  1049. }
  1050.  
  1051. void
  1052. _setcursortype(int t)
  1053. {
  1054.     register struct screen *sp;
  1055.  
  1056.     sp = getcursess()->screen;
  1057.     if (sp->sessmgr->cursor)
  1058.     {
  1059.     LOCKSCR(sp, 1);
  1060.     (*sp->sessmgr->cursor)(sp->sessmgr, sp->sesmdat, t);
  1061.     UNLOCKSCR(sp);
  1062.     }
  1063. }
  1064.  
  1065. int
  1066. kbread(void)
  1067. {
  1068.     register struct screen *sp;
  1069.  
  1070.     sp = getcursess()->screen;
  1071.     return (*sp->sessmgr->kbread)(sp->sessmgr, sp->sesmdat);
  1072. }
  1073.  
  1074. /*
  1075.  * The status entry point is different:  any routine may call the status output
  1076.  * routine, which calls the status switch entry for the Command screen.  If
  1077.  * that is NULL, we perform direct output without passing information to
  1078.  * rflush(); this avoids the flow control problems which have plagued previous
  1079.  * versions, although it requires that we duplicate parts of rflush() here
  1080.  * (and it's ugly).
  1081.  *
  1082.  * The numeric argument is presently ignored.  Eventually I may use it for
  1083.  * a positioning hint.
  1084.  */
  1085.  
  1086. void
  1087. sm_status(int pos, char *str)
  1088. {
  1089.     struct screen *cs;
  1090.  
  1091.     cs = Command->screen;
  1092.     if (cs->sessmgr->status)
  1093.     (*cs->sessmgr->status)(cs->sessmgr, cs->sesmdat, pos, str);
  1094.     else
  1095.     {
  1096.     if (cs->sessmgr->flags & SM_SUSPEND)
  1097.         return;
  1098.     if (!(cs->flags & SMS_ACTIVE))
  1099.         return;
  1100.     LOCKSCR(cs, 1);
  1101.     (*cs->sessmgr->rflush)(cs->sessmgr, cs->sesmdat);
  1102.     /* should translate \n to Eol */
  1103.     scputs(Command, str);
  1104. #if 0
  1105.     scputs(Command, Eol);
  1106. #endif
  1107.     (*cs->sessmgr->flush)(cs->sessmgr, cs->sesmdat);
  1108.     UNLOCKSCR(cs);
  1109.     }
  1110. }
  1111.